package com.tmt.annotation.parser;

import com.tmt.helper.ReflectHelper;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 多值枚举分析器, 用来分析BusinessLevel这样的多值枚举。
 * 作者：ThreeManTeam
 * 创建时间：2020-10-12 20:24
 */
public class MultiValueEnumParser {

    private static final int DefaultMaxOrdinal = 4;

    public static <T, K> String getEnumTNameByEnumK(T enumT, K enumK) {
        return getEnumTNameByEnumK(enumT, enumK, "getNameMap");
    }

    public static <T, K> String getEnumTNameByEnumK(T enumT, K enumK, String methodName) {
        String name = null;
        if (enumK != null) {
            Map<K, String> map = (Map<K, String>) ReflectHelper.invokeMethod(enumT, methodName, null, null);
            if (map != null && map.containsKey(enumK)) {
                name = map.get(enumK);
            }
        }

        if (enumK == null || name == null || name.trim().length() <= 0) {
            name = EnumAnnotationParser.getTitle(enumT);
        }
        return name;
    }

    public static <T, K> Map<String, String> getNameTitleMapByEnumK(Class<T> enum1Cls, K enumK) {
        Map<String, String> map = new LinkedHashMap<>();
        try {
            Method method = enum1Cls.getMethod("values", null);
            if (method != null) {
                T[] values = (T[]) method.invoke(null, null);
                if (values != null) {
                    for (T value : values) {
                        String title = getEnumTNameByEnumK(value, enumK);
                        String name = (String) ReflectHelper.invokeMethod(value, "name", null, null);
                        map.put(name, title);
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return map;
    }

    public static <T, K> List<T> geEnumTListByEnumK(Class<T> enum1Cls, K enumK) {
        List<T> list = new ArrayList<>();
        try {
            T[] values = null;
            Method method = enum1Cls.getMethod("values", null);
            if (method != null) {
                values = (T[]) method.invoke(null, null);
            }

            if (enumK != null && values != null) {
                for (T value : values) {
                    Map<K, String> map = (Map<K, String>) ReflectHelper.invokeMethod(value, "getNameMap", null, null);
                    if (map != null && map.containsKey(enumK)) {
                        list.add(value);
                    }
                }
            }

            if (list.isEmpty() && values != null) {
                list.addAll(Arrays.stream(values)
                        .filter(x -> {
                            int ordinal = (int) ReflectHelper.invokeMethod(x, "ordinal", null, null);
                            return ordinal <= DefaultMaxOrdinal;
                        })
                        .collect(Collectors.toList()));
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return list;
    }

    public static <T, K> T getMaxEnumTByEnumK(Class<T> enum1Cls, K enumK) {
        return getMaxEnumTByEnumK(enum1Cls, enumK, true);
    }

    public static <T, K> T getMinEnumTByEnumK(Class<T> enum1Cls, K enumK) {
        return getMaxEnumTByEnumK(enum1Cls, enumK, false);
    }

    public static <T, K> void getValidMapByEnumK(Class<T> enum1Cls, K enumK, List<Map<String, Object>> mapList) {
        List<Map<String, Object>> removedList = new ArrayList<>();
        List<T> validEnumAList = geEnumTListByEnumK(enum1Cls, enumK);
        mapList.forEach(x -> {
            T value = validEnumAList.stream().filter(t -> {
                String name = (String) ReflectHelper.invokeMethod(t, "name", null, null);
                return name != null && name.equals(x.get("id"));
            }).findFirst().orElse(null);

            if (value != null) {
                x.replace("text", getEnumTNameByEnumK(value, enumK));
            } else {
                removedList.add(x);
            }
        });
        mapList.removeAll(removedList);
    }


    private static <T, K> T getMaxEnumTByEnumK(Class<T> enum1Cls, K enumK, boolean isGetMax) {
        List<T> allValues = geEnumTListByEnumK(enum1Cls, enumK);
        T max = null;
        T min = null;
        for (T value : allValues) {
            if (max == null) {
                max = value;
                min = value;
                continue;
            }

            int maxOrdinal = (int) ReflectHelper.invokeMethod(max, "ordinal", null, null);
            int minOrdinal = (int) ReflectHelper.invokeMethod(min, "ordinal", null, null);
            int ordinal = (int) ReflectHelper.invokeMethod(value, "ordinal", null, null);
            if (maxOrdinal < ordinal) {
                max = value;
            }
            if (minOrdinal > ordinal) {
                min = value;
            }
        }
        return isGetMax ? max : min;
    }

}
